package com.jy.modules.cims.component.sysAssist;

import java.text.MessageFormat;
import java.util.Collection;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.jy.modules.cims.common.JResult;
import com.jy.modules.cims.common.open.api.JieYueApiHelper;
import com.jy.modules.cims.common.open.api.dto.EntryParameter;
import com.jy.modules.cims.common.open.api.dto.ResponseData;
import com.jy.modules.cims.common.open.api.enums.EntryResponseEnum;
import com.jy.modules.cims.common.open.api.log.InfoLogger;
import com.jy.modules.cims.common.sysUtils.CollectionsUtils;
import com.jy.modules.cims.common.sysUtils.SearchParamUtil;
import com.jy.modules.cims.common.sysUtils.SimpleStringUtils;
import com.jy.modules.cims.common.sysUtils.ViolationUtils;
import com.jy.modules.cims.component.api.SendInterfaceEnum;
import com.jy.modules.cims.data.interact.api.JieYueRequest;
import com.jy.modules.cims.data.interact.api.JieYueResponseData;
import com.jy.modules.platform.sysconfig.dto.SysConfigDTO;
import com.jy.modules.platform.sysconfig.service.SysConfigService;

@Service("com.jy.modules.cims.component.sysAssist.JieYueApiAssist")
public class JieYueApiAssist {
	private static Logger logger = LoggerFactory.getLogger(JieYueApiAssist.class);

	private final int DEFAULT_INTERVAL_TIMES = 0;

	private final String SERVICE_APPID = "{0}.service.appid";// 商户id
	private final String SERVICE_URL = "{0}.service.url";// 商户服务端地址
	private final String SERVICE_VERSION = "{0}.service.version";// 商户服务版本号
	private final String SERVICE_MD5KEY = "{0}.service.md5key";// 商户服务md5key
	private final String SERVICE_AESKEY = "{0}.service.aeskey";// 商户服务aeskey

	private final int SEND_LIST_MAX_SIZE = 1000;
	
	@Autowired
	@Qualifier("com.jy.modules.platform.sysconfig.service.SysConfigService")
	private SysConfigService sysConfigService;

	/**
	 * @description 根据商户appId获取API帮助类JieYueApiHelper
	 * @author shengzhoutao
	 * @param appId
	 *            捷越提供给商户id
	 * @return JieYueApiHelper API帮助类
	 */
	public JieYueApiHelper getJieYueApiHelperByAppId(final String appId) {
		String cooperorgCode = getCooperorgCodeByAppId(appId);
		//logger.info("机构编码cooperorgCode:" + cooperorgCode);
		if (SimpleStringUtils.hasText(cooperorgCode)) {
			return getJieYueApiHelperByCooperorgCode(cooperorgCode);
		}
		
		return null;
	}

	/**
	 * @description 根据商户appId获取机构编码
	 * @author shengzhoutao
	 * @param appId
	 *            捷越提供给商户id
	 * @return cooperorgCode 机构编码
	 */
	//@Ehcache
	public String getCooperorgCodeByAppId(final String appId) {
		SysConfigDTO sysConfigDTO = new SysConfigDTO();
		sysConfigDTO.setConfigValue(appId);

		List<SysConfigDTO> dataList = null;
		try {
			dataList = sysConfigService.searchSysConfig(SearchParamUtil.getSearchParam(sysConfigDTO));
		} catch (Exception e) {
			logger.error("根据商户appId查询对应的机构报错：", e);
		}

		if (CollectionsUtils.isEmpty(dataList)) {
			logger.error("商户appId没有配置");
			return null;
		}

		String configCode = "";
		for (SysConfigDTO sysConfig : dataList) {
			if (sysConfig.getConfigCode().contains(SERVICE_APPID.substring(3, SERVICE_APPID.length()))) {
				configCode = sysConfig.getConfigCode();
			}
		}

		logger.info("商户id配置编码configCode:" + configCode);
		if (!SimpleStringUtils.hasText(configCode)) {
			logger.error("商户appId没有配置");
			return null;
		}

		String cooperorgCode = configCode.substring(0, configCode.indexOf("."));
		logger.info("机构编码cooperorgCode:" + cooperorgCode);

		return cooperorgCode;
	}

	/**
	 * @description 根据机构编码获取API帮助类JieYueApiHelper
	 * @author shengzhoutao
	 * @param cooperorgCode
	 *            机构编码
	 * @return JieYueApiHelper API帮助类
	 */
	public JieYueApiHelper getJieYueApiHelperByCooperorgCode(final String cooperorgCode) {
		// 商户为我司提供id
		String appId = sysConfigService.queryValueByCode(MessageFormat.format(SERVICE_APPID, cooperorgCode));
		// 商户服务版本号
		String version = sysConfigService.queryValueByCode(MessageFormat.format(SERVICE_VERSION, cooperorgCode));
		// 商户服务md5key
		String md5key = sysConfigService.queryValueByCode(MessageFormat.format(SERVICE_MD5KEY, cooperorgCode));
		// 商户服务aeskey
		String aesKey = sysConfigService.queryValueByCode(MessageFormat.format(SERVICE_AESKEY, cooperorgCode));

		JieYueApiHelper helper = new JieYueApiHelper(new InfoLogger(JieYueApiHelper.class), md5key, aesKey, "UTF-8", null, appId, version);

		return helper;
	}

	/**
	 * @description 根根据商户appId获取商户服务端地址
	 * @author shengzhoutao
	 * @param appId
	 *            捷越提供给商户id
	 * @return serviceURL 商户服务端地址
	 */
	//@Ehcache
	public String getServiceURLByAppId(final String appId) {
		SysConfigDTO sysConfigDTO = new SysConfigDTO();
		sysConfigDTO.setConfigValue(appId);

		List<SysConfigDTO> dataList = null;
		try {
			dataList = sysConfigService.searchSysConfig(SearchParamUtil.getSearchParam(sysConfigDTO));
		} catch (Exception e) {
			logger.error("根据商户appId查询对应的机构报错：", e);
		}

		if (CollectionsUtils.isEmpty(dataList)) {
			logger.error("商户appId没有配置对应的机构");
			return null;
		}

		String configCode = dataList.get(0).getConfigCode();
		String cooperorgCode = configCode.substring(0, configCode.length() - 7);

		return getServiceURLByCooperorgCode(cooperorgCode);
	}

	/**
	 * @description 根根据商户机构编码获取商户服务端地址
	 * @author shengzhoutao
	 * @param cooperorgCode
	 *            机构编码
	 * @return serviceURL 商户服务端地址
	 */
	//@Ehcache
	public String getServiceURLByCooperorgCode(final String cooperorgCode) {
		String serviceURL = sysConfigService.queryValueByCode(MessageFormat.format(SERVICE_URL, cooperorgCode));

		return serviceURL;
	}

	/**
	 * @description 根据接收的参数验证签名
	 * @author shengzhoutao
	 * @param parameter
	 *            接收的参数
	 * @return true:验证签名通过;false:验证签名不通过
	 */
	public boolean checkSign(final EntryParameter parameter) {
		String timestamp = parameter.getTimestamp();
		logger.info("商户请求时间：" + timestamp);

		JieYueApiHelper helper = getJieYueApiHelperByAppId(parameter.getAppId());
		// 验证签名不通过
		if (!helper.checkSign(parameter)) {
			return false;
		}
		return true;
	}

	/**
	 * @description 根据接收的参数验证签名
	 * @author shengzhoutao
	 * @param parameter
	 *            接收的参数
	 * @param cooperorgCode
	 *            接收的参数
	 * @return true:验证签名通过;false:验证签名不通过
	 */
	public boolean checkSignByCooperorgCode(final EntryParameter parameter, final String cooperorgCode) {
		String timestamp = parameter.getTimestamp();
		logger.info("商户请求时间：" + timestamp);

		JieYueApiHelper helper = getJieYueApiHelperByCooperorgCode(cooperorgCode);
		// 验证签名不通过
		if (!helper.checkSign(parameter)) {
			return false;
		}
		return true;
	}

	/**
	 * @description 验证接收信息
	 * @param parameter
	 *            接收信息
	 * @return
	 */
	public <T> String validate(final T parameter) {
		if (null == parameter) {
			return "请求参数为空";
		}

		List<String> messageList = ViolationUtils.validate(parameter);
		if (CollectionsUtils.isEmpty(messageList)) {
			logger.info("验证接收信息通过！");
			return null;
		}

		String message = CollectionsUtils.convertToString(messageList, ";");
		logger.info("验证接收信息不通过：");
		logger.info(message);
		return message;
	}

	/**
	 * @description 调用商户系统接口，将数据发送商户。
	 *              根据不同机构编码，查找对应商户配置信息(商户appId、商户服务端地址、商户服务版本号、
	 *              商户服务md5key、商户服务aeskey)，根据配置信息和参数调用接口。
	 * @author shengzhoutao
	 * @param request
	 *            发送参数 ，输入值必须包含: <br>
	 *            机构编码<code>cooperorgCode</code> <br>
	 *            方法名<code>method</code> <br>
	 *            请求主体对象，可以是集合<code>content</code>
	 * @return ResponseData 返回对象<br>
	 */
	public <T> JieYueResponseData sendRequest(JieYueRequest request) {
		return sendInterval(request, 0);
	}

	/**
	 * @description sendInterval
	 * @param request
	 *            发送参数
	 * @param currentTime
	 * @return
	 */
	public <T> JieYueResponseData sendInterval(JieYueRequest request, int currentTime) {
		JieYueResponseData response = null;
		try {
			response = sendInterval(request);
		} catch (Exception e) {
			try {
				Thread.sleep(1000 * 5);
			} catch (InterruptedException e1) {
			}
			if (currentTime < DEFAULT_INTERVAL_TIMES) {
				response = sendInterval(request, ++currentTime);
			}
		}
		return response;
	}

	/**
	 * @description sendInterval
	 * @param request
	 *            发送参数
	 * @return JieYueResponseData
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public JieYueResponseData sendInterval(final JieYueRequest request) {
		JieYueResponseData newResponse = new JieYueResponseData();

		// 验证发送信息
		JResult jResult1 = validateSendParameter(request);
		logger.info("验证发送信息：" + JSON.toJSONString(jResult1));
		if (jResult1.isSuccess() == false) {
			newResponse.setMessage(jResult1.getErrMsg());
			newResponse.setRetCode(jResult1.getErrCode());
			return newResponse;
		}

		ResponseData responseData = null;
		JieYueApiHelper helper = getJieYueApiHelperByCooperorgCode(request.getCooperorgCode());
		String serviceURL = getServiceURLByCooperorgCode(request.getCooperorgCode());
		logger.info("发送begin==================>>");
		if (request.getContent() instanceof Collection) {
			// 发送list集合
			responseData = helper.sendRequestForList(serviceURL, request.getMethod(), request.getContent(), request.getClazz());
		} else {
			responseData = helper.sendRequest(serviceURL, request.getMethod(), request.getContent(), request.getClazz());
		}
		logger.info("发送end==================>>");
		logger.info("返回信息：" + JSON.toJSONString(responseData));
		
		// 验证响应信息
		ResponseData responseData2 = responseData;
		JResult jResult2 = validateResponseData(responseData2);
		logger.info("验证响应信息：" + JSON.toJSONString(jResult2));
		if (jResult2.isSuccess() == false) {
			newResponse.setMessage(jResult2.getErrMsg());
			newResponse.setRetCode(jResult2.getErrCode());
			return newResponse;
		}

		newResponse.setData(responseData.getData());
		newResponse.setMessage(responseData.getMessage());
		newResponse.setRetCode(responseData.getRetCode());

		if (CollectionsUtils.isNotEmpty(responseData.getDataList())) {
			newResponse.setDataList(responseData.getDataList());
		}
		return newResponse;
	}
	
	
	/**
	 * 验证发送信息
	 * @param request
	 * @return
	 */
	private JResult validateSendParameter(final JieYueRequest request) {
		JResult result = new JResult();
		result.setSuccess(false);

		// 验证该机构的商户appId
		String cooperorgCode = request.getCooperorgCode();
		logger.info("机构编码cooperorgCode:" + cooperorgCode);
		String appId = sysConfigService.queryValueByCode(MessageFormat.format(SERVICE_APPID, cooperorgCode));
		if (!SimpleStringUtils.hasText(appId)) {
			result.setErrMsg(EntryResponseEnum.FAILURE41004.getMessage());
			result.setErrCode(EntryResponseEnum.FAILURE41004.getCode());
			return result;
		}

		// 验证该机构的商户serviceURL
		String serviceURL = getServiceURLByCooperorgCode(cooperorgCode);
		if (!SimpleStringUtils.hasText(serviceURL)) {
			result.setErrMsg(EntryResponseEnum.FAILURE41005.getMessage());
			result.setErrCode(EntryResponseEnum.FAILURE41005.getCode());
			return result;
		}

		// 验证发送API接口名称
		String interfaceCode = request.getMethod();
		SendInterfaceEnum interfaceEnum = SendInterfaceEnum.getInterfaceEnumByInterfaceCode(interfaceCode);
		if (null == interfaceEnum) {// API接口名称取值不正确
			result.setErrMsg(java.text.MessageFormat.format("发送API接口名称[{0}]取值不正确。", new Object[] { interfaceCode }));
			result.setErrCode(EntryResponseEnum.FAILURE41005.getCode());
			return result;
		}

		// 验证发送请求内容
		Object content = request.getContent();
		if (null == content) {
			result.setErrMsg(EntryResponseEnum.FAILURE41009.getMessage());
			result.setErrCode(EntryResponseEnum.FAILURE41009.getCode());
			return result;
		}

		List<String> errorMessageList = ViolationUtils.validate(content);
		if (CollectionsUtils.isNotEmpty(errorMessageList)) {
			String errorMessageStr = CollectionsUtils.convertToString(errorMessageList, ";");
			logger.error("验证发送参数不通过：");
			logger.error(errorMessageStr);
			result.setErrMsg(EntryResponseEnum.FAILURE41003.getMessage() + "[" + errorMessageStr + "]");
			result.setErrCode(EntryResponseEnum.FAILURE41003.getCode());
			return result;
		}

		if (content instanceof Collection) {
			Collection<?> collection = (Collection<?>) content;
			if (CollectionsUtils.isEmpty(collection)) {
				result.setErrMsg(EntryResponseEnum.FAILURE41009.getMessage());
				result.setErrCode(EntryResponseEnum.FAILURE41009.getCode());
				return result;
			}

			if (collection.size() > SEND_LIST_MAX_SIZE) {
				result.setErrMsg(EntryResponseEnum.FAILURE41003.getMessage() + "[发送list集合的条数不通大于" + SEND_LIST_MAX_SIZE + "条]");
				result.setErrCode(EntryResponseEnum.FAILURE41003.getCode());
				return result;
			}
		}

		result.setSuccess(true);
		return result;
	}
	
	/**
	 * 验证响应信息
	 * @param responseData
	 * @return
	 */
	private JResult validateResponseData(final ResponseData<?> responseData) {
		JResult result = new JResult();
		result.setSuccess(false);
		if (null == responseData) {
			logger.info("响应信息不能为空!");
			result.setErrMsg(EntryResponseEnum.FAILURE41003.getMessage() + "[响应信息不能为空]");
			result.setErrCode(EntryResponseEnum.FAILURE41003.getCode());
			return result;
		}

		if (!SimpleStringUtils.hasText(responseData.getRetCode()) || !SimpleStringUtils.hasText(responseData.getMessage())
				|| !SimpleStringUtils.hasText(responseData.getMethod())) {
			logger.info("验证收到回复信息不通过：");
			result.setErrMsg(EntryResponseEnum.FAILURE41003.getMessage() + "[响应编码 retCode、响应信息 message、方法名 method 不能为空 ]");
			result.setErrCode(EntryResponseEnum.FAILURE41003.getCode());
			return result;
		}

		if (null == responseData.getData() && CollectionsUtils.isEmpty(responseData.getDataList())) {
			result.setErrMsg(EntryResponseEnum.FAILURE41003.getMessage() + "[响应主体信息 data或dataList 不能为空]");
			result.setErrCode(EntryResponseEnum.FAILURE41003.getCode());
			return result;
		}
		
		if (!responseData.isSign()) {
			logger.info("签名 sign 验证不通过！");
			result.setErrMsg(EntryResponseEnum.FAILURE41003.getMessage() + "[响应的签名 sign 验证不通过]");
			result.setErrCode(EntryResponseEnum.FAILURE41003.getCode());
			return result;
		}
		
		if (!responseData.successVisit()) {
			logger.info("收到异常信息：" + responseData.getMessage());
			result.setErrMsg(responseData.getMessage());
			result.setErrCode(responseData.getRetCode());
			return result;
		}
		
		result.setSuccess(true);
		return result;
	}
}
